package ar.edu.itba.pod.legajo48013.host;

import java.net.InetAddress;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

import ar.edu.itba.balance.api.AgentsBalancer;
import ar.edu.itba.balance.api.AgentsTransfer;
import ar.edu.itba.event.EventInformation;
import ar.edu.itba.event.RemoteEventDispatcher;
import ar.edu.itba.node.Node;
import ar.edu.itba.node.NodeInformation;
import ar.edu.itba.node.api.ClusterAdministration;
import ar.edu.itba.pod.legajo48013.balance.MyAgentsBalancer;
import ar.edu.itba.pod.legajo48013.balance.MyAgentsTransfer;
import ar.edu.itba.pod.legajo48013.cluster.ClusterImpl;
import ar.edu.itba.pod.legajo48013.event.ClusterEventDispatcher;
import ar.edu.itba.pod.legajo48013.event.EventThread;
import ar.edu.itba.pod.legajo48013.event.ProcessedEvent;
import ar.edu.itba.pod.legajo48013.event.RemoteEventDispatcherImpl;

public class Host {

	private NodeInformation node;
	private ClusterAdministration cluster;
	
	private ClusterEventDispatcher dispatcher;
	private RemoteEventDispatcher remoteDispatcher;
	private AgentsBalancer balancer;
	private AgentsTransfer transfer;
	
	
	private List<ProcessedEvent> processedEvents = new ArrayList<ProcessedEvent>();
	private BlockingQueue<EventInformation> pendingEvents = new LinkedBlockingQueue<EventInformation>();
	private Map<NodeInformation, Long> updates = new HashMap<NodeInformation, Long>();
	
	
	public Host(int port, String groupId) {
		try{
			String ip = InetAddress.getLocalHost().getHostAddress();
			String name = InetAddress.getLocalHost().getHostAddress() + ":" + port; 
	    	node = new NodeInformation(ip, port, name);
	    	cluster = new ClusterImpl(this, groupId);
			remoteDispatcher = new RemoteEventDispatcherImpl(this);
			dispatcher = new ClusterEventDispatcher(node.id(), remoteDispatcher);
			balancer = new MyAgentsBalancer(this);
			transfer = new MyAgentsTransfer();
			
			
			Registry registry = LocateRegistry.createRegistry(node.port());
			registry.bind(Node.CLUSTER_COMUNICATION, cluster);
			registry.bind(Node.DISTRIBUTED_EVENT_DISPATCHER, remoteDispatcher);
			registry.bind(Node.AGENTS_BALANCER, balancer);
			registry.bind(Node.AGENTS_TRANSFER, transfer);
			
	    	EventThread eventThread = new EventThread(this);
	    	eventThread.start();
						
		}catch (Exception e) {
			e.printStackTrace();
			// TODO: handle exception
		}
	}

	public AgentsBalancer getBalancer() {
		return balancer;
	}
	
	public AgentsTransfer getTransfer() {
		return transfer;
	}
	
	public ClusterAdministration getCluster() {
		return cluster;
	}
	public NodeInformation getNode() {
		return node;
	}

	public List<ProcessedEvent> getProcessedEvents() {
		return processedEvents;
	}
	
	public BlockingQueue<EventInformation> getPendingEvents() {
		return pendingEvents;
	}
	
	public void addPendingEvent(EventInformation event) {
		pendingEvents.add(event);
	}
	
	public Map<NodeInformation, Long> getUpdates() {
		return updates;
	}
	
	public ClusterEventDispatcher getDispatcher() {
		return dispatcher;
	}
	
}
